package com.jaynux.app;

import java.util.*;

import android.content.*;
import android.content.res.*;
import android.database.*;
import android.database.sqlite.*;
import android.graphics.*;
import android.os.*;
import android.util.*;
import android.view.*;
import android.view.SurfaceHolder.*;
import android.widget.*;

public class RandomRun extends SurfaceView implements Callback {
	private int mBGFarMoveX = 0;

	// 초기 메인 화면 이미지를 담당하는 변수 이다.
	private Bitmap mTitleBG2;

	// 실제로 경마 게임을 진행하는 핵심 Thread이다.
	// 따라서 이 Thread만 런처에서 제어를 해주면 게임을 전반적으로 제어가 가능하다.
	class ImgThread extends Thread{
		/**
		 * 상태 값들
		 */

		public static final int STATE_START = -1;
		public static final int STATE_PLAY = 0;
		public static final int STATE_LOSE = 1;
		public static final int STATE_PAUSE = 2;
		public static final int STATE_RUNNING = 3;
		public static final int STATE_RESUME = 4;
		
		// DB접근 컬럼들
		final int _ID = 0;
		final int TITLE = 1;
		final int PARTICIPATION = 2;
		final int WIN = 3;
		final int DISTANCE = 4;
		final int RACETIME = 5;

		private Cursor mCursorCondition;
		
		
		public int FIRST_START = 0;

		//꼴지를 기록하고 있다.
		public int LASTRANK =0;
		// 시작, 실행, 실행중, 끝 4가지 상태를 저장 한다.
		public int mState;

		/** surface View 실행 여부를 결정 한다. */
		private boolean mRun = false;
		private boolean mPause = true;

		/** Thread에게 끝을 알려주기 위한 Handler Message이다. */
		private Handler mHandler;

		// 경마시 사용하는 배경 이미지 저장
		private Bitmap mImgBack;

		private int cnt = 0;	// 처음에 1초를 멈추게할 변수

		Resources mRes;	// 리소스를 관리 하는 멤버

		private Bundle settingBundle; //세팅값이 저장된 번들

		private String mRaceResult;

		private SurfaceHolder mSurfaceHolder;

		int xBGCENTER = 0; // 처음시작 화면을 가운데로 저장하게할 변수
		int imgDownHeight = 0;
		int backWidth = 0;
		int xpos = 0;
		int ypos = 10;
		int horse_size = 0;
		int BGmove = 0;
		int CENTER = 0;
		
		int playerNum = 0;
		int mEndMeter; //경기장 길이
		int mNowMeter;
		Horses horses;
		
		int DIENUM = 4; 

		// 객체를 새로 생성할때 사용한다.
		Context mContext;

		// 시간을 표시하기 위함 TimeTask이다.
		private Timer mTimer = null;
		private TimerTask mTimerTask = null;
		// one second - used to update timer
		private int mTaskIntervalInMillis = 10;
		private int mTimerLimit = 0;
		// 화면에 시간을 표시해주는 문자열 멤버이다.
		private String mTimerValue = "0:00";

		public ImgThread(SurfaceHolder surfaceHolder, Context context, Handler handler){

			//현재 Thread의 상태를 저장하고 있다.
			mState = STATE_PLAY;
			//경마 결과를 저장 하는 문자열 멤버
			mRaceResult ="";
			//핸들러를 받아서 등록하여 준다.
			mHandler = handler;

			mSurfaceHolder = surfaceHolder;
			//리소스를 얻어온다.
			mRes = context.getResources();
			mImgBack = BitmapFactory.decodeResource(mRes, R.drawable.bglong);
			Bitmap mImgDownBack = BitmapFactory.decodeResource(mRes, R.drawable.down);

			int yBack = mImgBack.getHeight();
			backWidth = mImgBack.getWidth();
			imgDownHeight = mImgDownBack.getHeight();

			horse_size = (yBack - imgDownHeight)/4;
			ypos = horse_size+2;
			//중심이 되는 말을 중앙에 두기 위해서 계산을 한다.
			xBGCENTER = mImgBack.getWidth()/3;

			//삼국지 장수 하나하나는 독립적인 객체 상태로 존재한다.
			//객체는 다시 하나하나의 Thread로 구성된다.
			mContext = context;
			horses = new Horses(mContext);

			//타이머를 생성한다.
			mTimer = new Timer();
			//반복적으로 사용되어지면서 다시 실행할때 누적되어져 있으면 안되는 멤버들을 초기화 한다.
			setInitialGameState();

		}

		//게임중에 지속적으로 사용되어지는 멤버 변수를 초기화 한다.
		private void setInitialGameState() {
			
			mTimer = new Timer();
			mNowMeter=0;
			mTimerTask = null;
			//현재 거리를 초기화 한다.
			mNowMeter = 0; 
			//시간을 기록하면 변수 이다.
			mTimerLimit = 0;
			// 화면에 시간을 표시해주는 문자열 멤버이다.
			mTimerValue = "0:00";
		}
		//SettingActivity의 세팅 결과를 받아오는 메서드
		public void setSettingValue(Bundle b) {
			settingBundle=b;
			playerNum = b.getInt("playerNum");
			mEndMeter = b.getInt("meter");
			horses.setSettingValue(b);
			mMeterView.setText(""+mEndMeter);
		}
		// Surface View에 상황에 따라 다른 그림을 그려주기 위한 메서드
		private void doDraw(Canvas canvas) {

			if (mState == STATE_RUNNING) {
				doDrawRunning(canvas);
			} else if (mState == STATE_PLAY || mState == STATE_LOSE || mState == STATE_PAUSE) {
				if (mTitleBG2 == null) {
					mTitleBG2 = BitmapFactory.decodeResource(mRes, R.drawable.bglong);
				}
				doDrawPlay(canvas);
			}// end state play block
		}
		/**
		 * 현재 게임의 상태에 따라서 화면을 그려 주는 메서드들
		 */
		private void doDrawRunning(Canvas canvas) {

			boolean changed = true;
			
			//이거 땜에 처음1초의 준비기간때 캐릭터가 나오지 않아 이상해졌음 -_-;;cgj
			//현재와 다음을 비교하여 같다면 변화를 주지않고 같지않다면 변화를 허용한다.
			//for(int i = 0 ; i < playerNum; i++){
			//	if(horses.Horse[i].preStep != horses.Horse[i].LOCATION){
			//		changed = true;
			//	}
			//}

			if (changed) {

				// decrement the far background
				mBGFarMoveX = mBGFarMoveX - BGmove;

				// calculate the wrap factor for matching image draw
				int newFarX = mImgBack.getWidth() - (-mBGFarMoveX);

				// if we have scrolled all the way, reset to start
				if (newFarX <= 0) {
					mBGFarMoveX = 0;
					// only need one draw
					canvas.drawBitmap(mImgBack, mBGFarMoveX, 0, null);

				} else {
					// need to draw original and wrap
					canvas.drawBitmap(mImgBack, mBGFarMoveX, 0, null);
					canvas.drawBitmap(mImgBack, newFarX, 0, null);
				}

				cnt++;
				//해당 말의 Thread결과를 화면에 표시해주는 작업을 한다. 1/1000초 마다 1번씩 이 작업을 해준다.
				for (int i = 0; i < playerNum; i++) {					
					if(horses.Horse[CENTER].LOCATION < xBGCENTER){
						xpos = horses.Horse[i].LOCATION;
					}else if(horses.Horse[CENTER].LOCATION >= xBGCENTER && horses.Horse[CENTER].LOCATION <= mEndMeter-(surfaceWidth-xBGCENTER)){
						xpos = xBGCENTER - (horses.Horse[CENTER].LOCATION -horses.Horse[i].LOCATION);
						//BGmove = xBGCENTER - horses.Horse[CENTER].LOCATION;
						BGmove = horses.Horse[CENTER].mCurrentSpeed;
					}
					else if(horses.Horse[CENTER].LOCATION > mEndMeter-(surfaceWidth-xBGCENTER)){
						xpos = horses.Horse[i].LOCATION - (mEndMeter-(surfaceWidth-xBGCENTER)-xBGCENTER);
						if(xpos > surfaceWidth-100){
							xpos = surfaceWidth-100;
						}
						//시간을 측정한다. 종료시점에서 RANK가 정해짐
						if( (xpos == surfaceWidth-100) && (horses.Horse[i].getStopWatch() == 0)) {
							//종료시점이다. 현재시간을 객체에 기록한다.
							horses.Horse[i].setStopWatch(mTimerLimit);
						}
						BGmove = 0;
					}
					
					if(horses.Horse[i].obstableFlag == true) {
						horses.Horse[i].setShowDrawble();
						horses.Horse[i].mObstacleImage[horses.Horse[i].FRAME%4].setBounds(xpos+90, ypos + i*horse_size - horse_size, xpos + 190, ypos + i*horse_size);
						horses.Horse[i].mObstacleImage[horses.Horse[i].FRAME%4].draw(canvas);
						//기본 데미지 12-10 *4 = 8 따라서 7번 반복반한다.(칼질을)
						if(horses.Horse[i].FRAME > DIENUM*(12-horses.Horse[i].DAMAGE)) {
							horses.Horse[i].setDieDrawble();
							horses.Horse[i].obstableFlag = false;
						}
					} 
					//자기 자신이 해당하는 모션에 맞는 움직임을 표시하기위해 FRAME을 저장하고 있어야 한다.
					//FRAME은 각 말이 가지고있는 독립적인 변수인 것이다.
					horses.Horse[i].mHImage[horses.Horse[i].FRAME%4].setBounds(xpos, ypos + i*horse_size - horse_size, xpos + 100, ypos + i*horse_size);
					horses.Horse[i].mHImage[horses.Horse[i].FRAME%4].draw(canvas);

					
					int mini_y = surfaceHeight-imgDownHeight;
					horses.Horse[i].mHImage[horses.Horse[i].FRAME%4].setBounds((surfaceWidth-imgDownHeight/4)*horses.Horse[i].LOCATION/mEndMeter, mini_y + i*imgDownHeight/4, (surfaceWidth-imgDownHeight/4)*horses.Horse[i].LOCATION/mEndMeter+imgDownHeight/4, mini_y + i*imgDownHeight/4 + imgDownHeight/4);
					horses.Horse[i].mHImage[horses.Horse[i].FRAME%4].draw(canvas);
					
					for(int s = 0; s < playerNum; s++) { //현재 1등인 말이 항상 중심이 된다
						if(horses.Horse[CENTER].LOCATION < horses.Horse[s].LOCATION){
							CENTER = s;	
						}
						if(horses.Horse[LASTRANK].LOCATION > horses.Horse[s].LOCATION){
							// 실시간 거리 표시와 게임이 끝나는 시점을 인지하기위해서 사용한다.
							LASTRANK = s;
						}
						
							
					}
				}
			}
			changed = false;
		}

		private void doDrawPlay(Canvas canvas) {
			canvas.drawBitmap(mTitleBG2, 0, 0, null);
		}
		/**
		 * Does the work of updating timer
		 * 
		 */
		private void doCountDown() {
			//Log.d(TAG,"Time left is " + mTimerLimit);
			
			mTimerLimit = mTimerLimit + 1;
			//가장 후미에 오는 말의 위치가 현재까지 온 거리이다.
			mNowMeter = horses.Horse[LASTRANK].LOCATION;
			if(mNowMeter > mEndMeter) {
				mNowMeter = mEndMeter;
			}
			try {
				// 1/100 초를 바탕으로 시분 초를 구한다
				String timerLimit = "000000"+mTimerLimit;
				int lenth = timerLimit.length();
				String milis = timerLimit.substring(lenth-2, lenth); //마지막 두자리는 ms이다
				String s = timerLimit.substring(0, lenth-2);
				int hour = Integer.parseInt(s)/3600;
				int min = (Integer.parseInt(s)%3600)/60;
				int sec = Integer.parseInt(s)%60;
				mTimerValue = hour+"시:"+min+"분:"+sec+"초"+milis;
			} catch (Exception e1) {
				Log.e(TAG, "doCountDown threw " + e1.toString());
			}

			Message msg = mHandler.obtainMessage();

			Bundle b = new Bundle();
			b.putString("timeinfo", mTimerValue);
			b.putString("endmeterinfo",String.format("%d", mEndMeter));
			b.putString("nowmeterinfo",String.format("%d", mNowMeter));

			//끝을 내야되는 시점인지를 판단한다.
			if (mNowMeter >= mEndMeter) {
				/* b.putString("STATE_LOSE", "" + STATE_LOSE);


                mState = STATE_LOSE;
				 */

			} else {

				mTimerTask = new TimerTask() {
					public void run() {
						doCountDown();
					}
				};

				mTimer.schedule(mTimerTask, mTaskIntervalInMillis);
			}

			//this is how we send data back up to the main JetBoyView thread.
			//if you look in constructor of JetBoyView you will see code for
			//Handling of messages. This is borrowed directly from lunar lander.
			//Thanks again!
			msg.setData(b);
			mHandler.sendMessage(msg);
		}
		public void DoPause() {
			for (int i = 0; i < playerNum; i++) {
				horses.Horse[i].mPause = false;
			}
			mPause = false;
		}
		
		public synchronized void DoResume() {
			for (int i = 0; i < playerNum; i++) {
				horses.Horse[i].mPause = true;
			}
			mPause = true;
			if(mState != STATE_LOSE && mState != STATE_PLAY)
				setGameState(STATE_RESUME);
		}
		
		public void run(){

			//surface View를 만들지 않았다면 이 과정을 반복하여 수행하지 않는다.
			while (mRun) {
				while(mPause) {
					Canvas c = null;
					try {

						// 게임중일 때만 시간을 측정 한다.
						if (mState == STATE_RUNNING) {
							// 시간과 관련된 함수처리
							if (mTimerTask == null) {
								mTimerTask = new TimerTask() {
									public void run() {
										doCountDown();
									}
								};

								mTimer.schedule(mTimerTask, mTaskIntervalInMillis);

							}// end of TimerTask init block
						} else if (mState == STATE_PAUSE){
							mTimer.cancel();
						}
						c = mSurfaceHolder.lockCanvas(null);
						// synchronized (mSurfaceHolder) {

						doDraw(c);
						//부하를 줄이기 위해 딜레이를 준다.
						sleep(1);
						// kick off the timer task for counter update if not already

						// 말들이 결승점에 도달 하였는지 체크 한다.
						if(horses.NUMBER > playerNum){

							Log.d(TAG, "mHandler message ~~");
							//속도 향상을 위해서 메시지 풀에서 비슷한 메시지를 꺼내 재사용 한다.
							Message msg = mHandler.obtainMessage();

							for(int i = 1; i <= playerNum; i++){
								horses.Horse[i-1].stop();
								for(int j = 0; j < playerNum; j++){
									if(i == horses.Horse[j].RANK){
										//등수를 누적하여 저장을 한다.
										String panalty = "";
										if(i == 1) {
											String timerLimit = "000000"+horses.Horse[j].getStopWatch();
											int lenth = timerLimit.length();
											String milis = timerLimit.substring(lenth-2, lenth);
											String s = timerLimit.substring(0, lenth-2);
											int hour = Integer.parseInt(s)/3600;
											int min = (Integer.parseInt(s)%3600)/60;
											int sec = Integer.parseInt(s)%60;
											String time = hour+"시:"+min+"분:"+sec+"초"+milis;
											if(settingBundle.getString("first") != null)
												panalty = settingBundle.getString("first");
											mRaceResult += i+"등 : "+horses.Horse[j].NAME+
											"("+horses.Horse[j].playerName+")"+"\n"+
											"Panalty : "+settingBundle.getString("first")+"\n" +
											"Time : "+time+"\n";
											
											//j번째 말이 i등일때의 처리 문이다. 따라서 이곳에서 DB 작업을 하여 준다.
											mCursorCondition = mDb.rawQuery("select _id, title, participation, win, distance, racetime from notes " +
													"where title='"+horses.Horse[j].NAME+"'",null);
											if(mCursorCondition.moveToFirst() == false){
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",1);
												row.put("win",1);
												row.put("distance",mEndMeter);
												row.put("racetime",horses.Horse[j].getStopWatch());
												mDb.insert("notes",null,row);
											}
											else {
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",mCursorCondition.getInt(PARTICIPATION)+1);
												row.put("win",mCursorCondition.getInt(WIN)+1);
												row.put("distance",mCursorCondition.getInt(DISTANCE)+mEndMeter);
												row.put("racetime",mCursorCondition.getFloat(RACETIME)+horses.Horse[j].getStopWatch());	
												mDb.update("notes", row, "title = '"+horses.Horse[j].NAME+"'",null);	
											}
											
										} else if(i == 2) {
											String timerLimit = "000000"+horses.Horse[j].getStopWatch();
											int lenth = timerLimit.length();
											String milis = timerLimit.substring(lenth-2, lenth);
											String s = timerLimit.substring(0, lenth-2);
											int hour = Integer.parseInt(s)/3600;
											int min = (Integer.parseInt(s)%3600)/60;
											int sec = Integer.parseInt(s)%60;
											String time = hour+"시:"+min+"분:"+sec+"초"+milis;
											if(settingBundle.getString("second") != null)
												panalty = settingBundle.getString("second");
											mRaceResult += i+"등 : "+horses.Horse[j].NAME+
											"("+horses.Horse[j].playerName+")"+"\n"+
											"Panalty : "+settingBundle.getString("second")+"\n" +
											"Time : "+time+"\n";
											
											//j번째 말이 i등일때의 처리 문이다. 따라서 이곳에서 DB 작업을 하여 준다.
											mCursorCondition = mDb.rawQuery("select _id, title, participation, win, distance, racetime from notes " +
													"where title='"+horses.Horse[j].NAME+"'",null);
											if(mCursorCondition.moveToFirst() == false){
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",1);
												row.put("win",0);
												row.put("distance",mEndMeter);
												row.put("racetime",horses.Horse[j].getStopWatch());
												mDb.insert("notes",null,row);
											}
											else {
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",mCursorCondition.getInt(PARTICIPATION)+1);
												row.put("win",mCursorCondition.getInt(WIN)+0);
												row.put("distance",mCursorCondition.getInt(DISTANCE)+mEndMeter);
												row.put("racetime",mCursorCondition.getFloat(RACETIME)+horses.Horse[j].getStopWatch());	
												mDb.update("notes", row, "title = '"+horses.Horse[j].NAME+"'",null);	
											}
										} else if(i == 3){
											String timerLimit = "000000"+horses.Horse[j].getStopWatch();
											int lenth = timerLimit.length();
											String milis = timerLimit.substring(lenth-2, lenth);
											String s = timerLimit.substring(0, lenth-2);
											int hour = Integer.parseInt(s)/3600;
											int min = (Integer.parseInt(s)%3600)/60;
											int sec = Integer.parseInt(s)%60;
											String time = hour+"시:"+min+"분:"+sec+"초"+milis;
											if(settingBundle.getString("third") != null)
												panalty = settingBundle.getString("third");
											mRaceResult += i+"등 : "+horses.Horse[j].NAME+
											"("+horses.Horse[j].playerName+")"+"\n"+
											"Panalty : "+panalty+"\n" +
											"Time : "+time+"\n";
											
											//j번째 말이 i등일때의 처리 문이다. 따라서 이곳에서 DB 작업을 하여 준다.
											mCursorCondition = mDb.rawQuery("select _id, title, participation, win, distance, racetime from notes " +
													"where title='"+horses.Horse[j].NAME+"'",null);
											if(mCursorCondition.moveToFirst() == false){
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",1);
												row.put("win",0);
												row.put("distance",mEndMeter);
												row.put("racetime",horses.Horse[j].getStopWatch());
												mDb.insert("notes",null,row);
											}
											else {
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",mCursorCondition.getInt(PARTICIPATION)+1);
												row.put("win",mCursorCondition.getInt(WIN)+0);
												row.put("distance",mCursorCondition.getInt(DISTANCE)+mEndMeter);
												row.put("racetime",mCursorCondition.getFloat(RACETIME)+horses.Horse[j].getStopWatch());	
												mDb.update("notes", row, "title = '"+horses.Horse[j].NAME+"'",null);	
											}
										} else {
											String timerLimit = "000000"+horses.Horse[j].getStopWatch();
											int lenth = timerLimit.length();
											String milis = timerLimit.substring(lenth-2, lenth);
											String s = timerLimit.substring(0, lenth-2);
											int hour = Integer.parseInt(s)/3600;
											int min = (Integer.parseInt(s)%3600)/60;
											int sec = Integer.parseInt(s)%60;
											String time = hour+"시:"+min+"분:"+sec+"초"+milis;
											if(settingBundle.getString("fourth") != null)
												panalty = settingBundle.getString("fourth");
											mRaceResult += i+"등 : "+horses.Horse[j].NAME+
											"("+horses.Horse[j].playerName+")"+"\n"+
											"Panalty : "+panalty+"\n" +
											"Time : "+time+"\n";
											
											//j번째 말이 i등일때의 처리 문이다. 따라서 이곳에서 DB 작업을 하여 준다.
											mCursorCondition = mDb.rawQuery("select _id, title, participation, win, distance, racetime from notes " +
													"where title='"+horses.Horse[j].NAME+"'",null);
											if(mCursorCondition.moveToFirst() == false){
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",1);
												row.put("win",0);
												row.put("distance",mEndMeter);
												row.put("racetime",horses.Horse[j].getStopWatch());
												mDb.insert("notes",null,row);
											}
											else {
												ContentValues row = new ContentValues();			
												row.put("title",horses.Horse[j].NAME);
												row.put("participation",mCursorCondition.getInt(PARTICIPATION)+1);
												row.put("win",mCursorCondition.getInt(WIN)+0);
												row.put("distance",mCursorCondition.getInt(DISTANCE)+mEndMeter);
												row.put("racetime",mCursorCondition.getFloat(RACETIME)+horses.Horse[j].getStopWatch());	
												mDb.update("notes", row, "title = '"+horses.Horse[j].NAME+"'",null);	
											}
										}
									}
								}
							}
							//객체를 새로 생성한다.
							horses = new Horses(mContext);
							horses.setSettingValue(settingBundle);
							//번들 객체를 생성하여 그곳에 경마 결과를 저장하여 핸들러로 보내준다.
							Bundle b = new Bundle();
							//최종적인 등수 결과를 저장 한다.
							b.putString("text", mRaceResult);
							//상태를 저장 한다.
							b.putString("STATE_LOSE", "" + STATE_LOSE);
							// 상태를 변경 한다.
							mState = STATE_LOSE;
							// 경기장 거리를 저장한다
							b.putInt("meter", mEndMeter);
							//다음 사용을 위해 초기화 한다.
							mRaceResult="";

							//horses.NUMBER =1;
							//메시지를 저장하여 핸들러로 전송하여준다.
							msg.setData(b);
							mHandler.sendMessage(msg);

						}
					}
					catch (InterruptedException e) {
						e.printStackTrace();
					}finally{
						if (c != null) {
							mSurfaceHolder.unlockCanvasAndPost(c);
						}
					}// end finally block
				}
				try {
					sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}	
		}

		/**
		 * 현재 surface view의 상태를 가져온다.
		 * @return
		 */
		public int getGameState() {
			synchronized (mSurfaceHolder) {
				return mState;
			}
		}

		/**
		 * 현재 surface view의 상태를 설정하고 그에 맞는 작업을 처리하여 준다.
		 * main actvity에서 작업을 제어하기 위함이다.
		 * 
		 * @see #setState(int, CharSequence)
		 * @param mode one of the STATE_* constants
		 */
		public void setGameState(int mode) {
			synchronized (mSurfaceHolder) {
				setGameState(mode, null);
			}
		}

		/**
		 * 상태에 따른 작업을 처리해 준다.
		 * 
		 * @param state
		 * @param message
		 */
		public void setGameState(int state, CharSequence message) {

			synchronized (mSurfaceHolder) {

				// change state if needed
				if (mState != state) {
					mState = state;
				}

				if (mState == STATE_LOSE) {
							
				} else if(mState == STATE_RESUME) {
					
					mTimerTask = new TimerTask() {
						public void run() {
							doCountDown();
						}
					};
					mTimer = new Timer();
					mTimer.schedule(mTimerTask, mTaskIntervalInMillis);
					mState = STATE_RUNNING;
				} else if (mState == STATE_RUNNING) {

					//다시 시작할떄 문제가 생기지 않도록 초기화를 해준다.
					//단 이 초기화는 반복적으로 해줘야대는 것들만 골라서 만들어 놓았다.
					setInitialGameState();

					//삼국지 말 Thread를 시작 시킨다.
					for(int i = 0 ; i < playerNum; i++){
						horses.Horse[i].start();
					}

				} 

			}
		}

		/**
		 * surface view의 실행여부를 결정하는
		 * mRun을 제어한다.
		 * 
		 * @param b true to run, false to shut down
		 */
		public void setRunning(boolean b) {
			mRun = b;
		}

	} // ImgThread End

	//외부로 반환 하기 위한 Thrad 멤버
	private ImgThread thread;

	public static final String TAG = "SAMGUKJI RACE";

	private TextView mMeterView;
	private TextView mTimerView;

	private Button mButtonRetry;
	private Button mButtonMain; 
	private TextView mTextView;
	//main으로부터 얻어온 db객체를 저장한다.
	private SQLiteDatabase mDb;

	int surfaceWidth;
	int surfaceHeight;
	public RandomRun(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub

		//표면에 변화가 생길 때의 이벤트를 처리할 콜백을 자신으로 지정 한다.
		SurfaceHolder holder = getHolder();
		holder.addCallback(this);

		/*
		 * surfaceCreated()에 의해서만 Thread가 생성 되어지는것을 허락한다.
		 */
		if (isInEditMode() == false) {
			thread = new ImgThread(holder, context,new Handler() {
			
				public void handleMessage(Message m) {
					//시간이 아니기 떄문에 구지 핸들러로 처리 할 필요가 없다.
					//경마 이동 거리를 실시간으로 표시 한다. 
					mMeterView.setText(m.getData().getString("nowmeterinfo")+"/"
							+m.getData().getString("endmeterinfo"));
					mTimerView.setText(m.getData().getString("timeinfo"));

					//메시지에서 LOSE 상태인것을 꺼낸다.
					if (m.getData().getString("STATE_LOSE") != null) {
						//mButtonRestart.setVisibility(View.VISIBLE);
						mButtonRetry.setVisibility(View.VISIBLE);
						mButtonMain.setVisibility(View.VISIBLE);
						mMeterView.setVisibility(View.INVISIBLE);

						mTextView.setVisibility(View.VISIBLE);

						Log.d(TAG, "the total was ");

						//최종적인 결과를 화면에 표시한다.
						mTextView.setTextSize(16);
						mTextView.setText(m.getData().getString("text"));
						
						//거리를 깔끔하게 맞추기위해서 다시한번 표시한다. 
						//확률적으로 10012 이런식으로 약간 벗어나게된다.
						mMeterView.setText(m.getData().getString("endmeterinfo")+"/"
								+m.getData().getString("endmeterinfo"));

						mMeterView.setText(""+m.getData().getInt("meter"));
						mTextView.setHeight(20);


					}
				}//end handle msg
			});
		}
		setFocusable(true); // 터치 mode와 관련된 함수 이다.
	}


	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
		surfaceWidth = width;
		surfaceHeight = height;
	}

	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		if(thread.FIRST_START != 0 && (thread.mState == thread.STATE_LOSE || thread.mState == thread.STATE_PLAY)) {	
			thread.DoResume();
		} else if (thread.mState == thread.STATE_PAUSE) {
			thread.mPause = true;
		}
		else {
			thread.FIRST_START++;
			thread.setRunning(true); //run이 수행되어 지도록 한다.
			thread.start();
		}
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		if(thread.mState == thread.STATE_PAUSE || thread.mState == thread.STATE_LOSE || thread.mState == thread.STATE_PLAY) {
			thread.DoPause();
		} else {
			boolean retry = true;
			thread.setRunning(false);
			while(retry){
				try{
					thread.join();
					retry = false;
				}catch(InterruptedException e){
				}
			}
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// TODO Auto-generated method stub
		return super.onKeyDown(keyCode, event);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		//thread.setX((int)event.getX());
		//event.getAction();
		/*thread.init();
		for(int i =0; i<4; i++) {
			thread.horses.Horse[i].init();
		}*/
		return true;
	}
	/**
	 * 외부에서 surface view main Thread를 얻을 수 있다.
	 * 
	 * @return the animation thread
	 */
	public ImgThread getThread() {
		return thread;
	}

	/**
	 * 거리를 표시해 주기위해 외부로 부터 TextView 객체를 받아온다.
	 * @param tv
	 */
	public void setMeterView(TextView tv) {
		mMeterView = tv;
	}

	/*
	 * 시간을 표시해주기 위해서 TextView 객체를 받아온다.
	 */
	public void setTimerView(TextView tv){
		mTimerView = tv;
	}

	/**
	 * 다시 시작을위해 버튼 객체를 외부로 부터 받아온다.
	 * 
	 * @param _buttonRetry
	 * 
	 */
	public void SetButtonView(Button _buttonRetry) {
		mButtonRetry = _buttonRetry;
		//  mButtonRestart = _buttonRestart;
	}

	public void SetButtonMain(Button _buttonRetry) {
		mButtonMain = _buttonRetry;
		//  mButtonRestart = _buttonRestart;
	}
	
	//we reuse the help screen from the end game screen.
	public void SetTextView(TextView textView) {
		mTextView = textView;
	}
	
	public void setSQLiteDB(SQLiteDatabase arDb){
		mDb = arDb;
	}
}
